/**
 *  jQuery.jsonengine.utils
 */
(function($) {
	$.jsonengine.utils = function(){};
	$.jsonengine.utils.version = '03-05-2011';
	/**
	 * htmlタグをエスケープします
	 */
	$.jsonengine.utils.escapetag = function(o) {
		if (Object.prototype.toString.call(o) !== '[object String]') return o;
		return o.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
	};
	/**
	 * jsonデータをhtmlリスト形式へ
	 */
	$.jsonengine.utils.json2html = function(json) {
		if (!json) {
			return json;
		} else if (Object.prototype.toString.call(json) === '[object Object]') {
			var dl = $('<dl class="object_Object">');
			for ( var key in json) {
				//将来的に<span class="object">は埋め込まない。html2jsonに任せる。
				dl.append($('<span class="object">')
					.append($('<dt class="key">').html( this.escapetag(key) ))
					.append($('<dd class="value">').html( this.escapetag( this.json2html(json[key]) ))));
			}
			return dl;
		} else if (Object.prototype.toString.call(json) === '[object Array]') {
			var ol = $('<ol class="object_Array">');
			var json_length = json.length;
			for ( var i = 0; i < json_length; i++) {
				ol.append($('<li class="value">').html( this.escapetag( this.json2html(json[i]) )));
			}
			return ol;
		} else {
			return json;
		}
	};
	/**
	 * htmlリストをjsonデータ形式へ
	 */
	$.jsonengine.utils.html2json = function(html) {
		//TODO dt,dd ペアを<span class="object">で囲む処理を書く。
		html2json_exec = function(src) {
			if (!src) return src;
			src = $(src);
			object_Object = src.attr('class').match(/object_Object/);
			object_Array = src.attr('class').match(/object_Array/);
			if (object_Object) {
				var object = {};
				var children = src.children();
				for (var i = 0; i < children.length; i++) {
					var o = children.eq(i);
					//ネストしているか判定
					if (!o.children().filter('.value').find('dl,ol').length) {
						object[o.children().filter('.key').eq(0).text()] = 
							o.children().filter('.value').eq(0).text();
					} else {
						object[o.children().filter('.key').eq(0).text()] = 
							html2json_exec(o.children().filter('.value').eq(0).children()[0]);
					}
				}
				return object;
			} else if (object_Array) {
				var array = [];
				var children = src.children();
				for (var i = 0; i < children.length; i++) {
					var grandChildren = children.eq(i).children();
					if (grandChildren.length == 0) {
						array[i] = children.eq(i).text();
					} else {
						array[i] = html2json_exec(grandChildren);
					}
				}
				return array;
			} else {
				return src;
			}
		}
		return html2json_exec(html);
	};
})(jQuery);

/**
 *  jQuery.jsonengine.fn
 */
(function($) {
	$.jsonengine.fn = function(){};
	$.jsonengine.fn.version = '03-05-2011';
	/**
	 * htmlに記述された情報からdocType文字列を構築する
	 */
	$.jsonengine.fn.docType = function(o) {
		try {
			return $(o)
				.attr('class')
				.match(/_je_.*?\b/)[0]
				.replace('_je_','');
		} catch(e) {
			return;
		}
	};
	/**
	 * htmlに記述された情報からURL文字列を構築する
	 */
	$.jsonengine.fn.url = function(o) {
		d = this.docType(o);
		if(!d) return;
		return '/_je/' + d + $(o)
			.find('span.query').eq(0)
			.text()
			.trim();
	};
	/**
	 * htmlに記述された情報からリスト表示に使用されるリンクを取得する。
	 * このリンクを用いいてRoR crudライクなアプリが書けるようになる。
	 * TODO 実装とテストを書く
	 */
	$.jsonengine.fn.link = function(o) {
	};
})(jQuery);

/**
 *  jQuery.jsonengine.fn.basic
 */
(function($) {
	$.jsonengine.fn.basic = function(){};
	$.jsonengine.fn.basic.version = '03-05-2011';
	/**
	 * jsonengineからデータ読み込み成功した際のコールバック関数
	 */
	$.jsonengine.fn.basic.success_LOAD = function(o, response, status) {
		tmp = {};
		tmp.query = o.find('span.query');
		o.empty();
		o.append(tmp.query);
		e = $.jsonengine.utils.json2html(response);
		if(e.html()!==''){
			e.addClass('result');
			o.append(e);
			/*
			 * eにonclick処理を加える。
			 *  1.すでにリスト表示されているデータを元にフォームデータをセット
			 *  2.新たにjsonengineからデータを取得しセット
			 *  3.span.linkがある場合はそのリンクを表示。リンク先にパラメータ_docIdを渡して遷移
			 */
			//case 1
			$('.object_Object').click(function(){
				form = $('form[class*=_je_'+$.jsonengine.fn.docType(o)+']:not(form.search)');
				for (i = 0; i < form.length; i++) {
					r = {};
					for (k in form.eq(i).values()) {
						r[k] = "";
					}
					form.eq(i).values(r);
					form.eq(i).values($.jsonengine.utils.html2json(this));
				}
			});
			//case 2
			//case 3
		}
	};
	/**
	 * jsonengineからデータ読み込み失敗した際のコールバック関数
	 */
	$.jsonengine.fn.basic.error_LOAD = function(o, xhr, status, thrown){
		o.append($('<div class="error">')
			.append('status:')
				.append($('<span style="color:red;font-weight:bold;">')
					.append(status)));
	};
	/**
	 * jsonengineから1件取得が成功した際のコールバック関数
	 */
	$.jsonengine.fn.basic.success_GET = function(o, response, status) {
		$(o).values(response);
	};
	/**
	 * jsonengineから1件取得がが失敗した際のコールバック関数
	 */
	$.jsonengine.fn.basic.error_GET= function(o, xhr, status, thrown){
		console.log('error GET')
	};
	/**
	 * jsonengineへ新規登録が成功した際のコールバック関数
	 */
	$.jsonengine.fn.basic.success_POST = function(o, response, status) {
		if ($(o).attr('class').match(/afterclear/)) {
			r = {};
			for (k in $(o).values()) {
				r[k] = "";
			}
			$(o).values(r);
		} else {
			$(o).values(response);
		}
		$('*:[class*=_je_]:not(form:[class*=_je_])')._LOAD();
	};
	/**
	 * jsonengineへ新規登録が失敗した際のコールバック関数
	 */
	$.jsonengine.fn.basic.error_POST = function(o, xhr, status, thrown){
		console.log('error POST')
	};
	/**
	 * jsonengineへ更新が成功した際のコールバック関数
	 */
	$.jsonengine.fn.basic.success_PUT = function(o, response, status) {
		if ($(o).attr('class').match(/afterclear/)) {
			r = {};
			for (k in $(o).values()) {
				r[k] = "";
			}
			$(o).values(r);
		} else {
			$(o).values(response);
		}
		$('*:[class*=_je_]:not(form:[class*=_je_])')._LOAD();
	};
	/**
	 * jsonengineへ更新が失敗した際のコールバック関数
	 */
	$.jsonengine.fn.basic.error_PUT = function(o, xhr, status, thrown){
		console.log('error PUT')
	};
	/**
	 * jsonengineで削除が成功した際のコールバック関数
	 */
	$.jsonengine.fn.basic.success_DELETE = function(o, response, status) {
		r = {};
		for (k in $(o).values()) {
			r[k] = "";
		}
		$(o).values(r);
		$('*:[class*=_je_]:not(form:[class*=_je_])')._LOAD();
	};
	/**
	 * jsonengineで削除が失敗した際のコールバック関数
	 */
	$.jsonengine.fn.basic.error_DELETE = function(o, xhr, status, thrown){
		console.log('error DELETE')
	};
	/**
	 * メソッド名により使用するデフォルトの成功処理関数を返す
	 */
	$.jsonengine.fn.basic.success = function(o){
		switch (o.type) {
			case 'GET':
				if (o.object.jquery) {
					return this.success_LOAD;
				} else {
					return this.success_GET;
				}
			case 'POST':
				return this.success_POST;
			case 'PUT':
				return this.success_PUT;
			case 'DELETE':
				return this.success_DELETE;
			default :
				break;
		}
		return;
	};
	/**
	 * メソッド名により使用するデフォルトの成功処理関数を返す
	 */
	$.jsonengine.fn.basic.error = function(o){
		switch (o.type) {
			case 'GET':
				if (o.object.jquery) {
					return this.error_LOAD;
				} else {
					return this.error_GET;
				}
			case 'POST':
				return this.error_POST;
			case 'PUT':
				return this.error_PUT;
			case 'DELETE':
				return this.error_DELETE;
			default :
				break;
		}
		return;
	};
	/**
	 * jsonengineプラグイン定義のベース関数
	 */
	$.jsonengine.fn.basic.base = function(o){
		o.success = (o.success)? o.success : this.success(o);
		o.error   = (o.error)? o.error : this.error(o);
		if (o.object.jquery) {
			o.url = $.jsonengine.fn.url(o.object);
		} else {
			if (o.type === 'GET' || o.type === 'DELETE') {
				o.url = $.jsonengine.fn.url(o.object) + '/' + o.data._docId;
				o.data = '';
			} else {
				o.url = $.jsonengine.fn.url(o.object);
			}
		}
		if (!o.url) return;
		$.jsonengine.ajax({
			"type"    : o.type,
			"url"     : o.url,
			"data"    : o.data,
			"success" : $.jsonengine.success(o.object, o.success),
			"error"   : $.jsonengine.error(o.object, o.error)
		});
	};
	// プラグインの定義
	$.fn.extend( {
		/**
		 * jsonengineから取得したjsonをhtmlリストへ変換し表示用要素内に追加するプラグイン
		 */
		_LOAD : function(s, e) {
			for(i=0; i < this.length; i++){
				o = {
					"object" :this.eq(i),
					"type"   :"GET",
					"data"   :"",
					"success":s,
					"error"  :e
				};
				$.jsonengine.fn.basic.base(o);
			}
			return this;
		},
		/**
		 * フォームに入力されたデータを元にjsonengineへ問い合わせ、フォームに読み込むプラグイン
		 * 問い合わせは_docIdを用いる
		 */
		_GET : function(s, e) {
			o = {
				"object" :this.get(0).form,
				"type"   :"GET",
				"success":s,
				"error"  :e
			};
			o.data = $(o.object).values();
			$.jsonengine.fn.basic.base(o);
			return this;
		},
		/**
		 * フォームに入力されたデータをjsonengineへ登録するプラグイン
		 */
		_POST : function(s, e) {
			o = {
				"object" :this.get(0).form,
				"type"   :"POST",
				"success":s,
				"error"  :e
			};
			o.data = $(o.object).values();
			if (o.data._docId === '') delete o.data._docId;
			$.jsonengine.fn.basic.base(o);
			return this;
		},
		/**
		 * フォームに入力されたデータをjsonengineへ更新するプラグイン
		 */
		_PUT : function(s, e) {
			o = {
				"object" :this.get(0).form,
				"type"   :"PUT",
				"success":s,
				"error"  :e
			};
			o.data = $(o.object).values();
			$.jsonengine.fn.basic.base(o);
			return this;
		},
		/**
		 * フォームに入力されたデータを元にjsonengineへ問い合わせ、フォームに読み込むプラグイン
		 */
		_DELETE : function(s, e) {
			o = {
				"object" :this.get(0).form,
				"type"   :"DELETE",
				"success":s,
				"error"  :e
			};
			o.data = $(o.object).values();
			$.jsonengine.fn.basic.base(o);
			return this;
		},
		/**
		 * フォームに入力されたデータを元にjsonengineへ問い合わせ、フォームに読み込むプラグイン
		 * 問い合わせはシステムのパラメータ以外の入力データで構築する
		 */
		_SEARCH : function(s, e) {
			values = $(this.get(0).form).values();
			delete values._docId;
			delete values._createdAt;
			delete values._updatedAt;
			delete values._userName;
			docType = $.jsonengine.fn.docType(this.get(0).form);
			elements = $('*:[class*=_je_' + docType + ']:not(form:[class*=_je_])');
			for (i = 0; i < elements.length; i++) {
				tmp = elements.eq(i).children().filter('span.query').eq(0).text();
				query = '';
				for (k in values) {
					if (values[k] !== '') {
						query += '&cond=' + k + '.eq.' + values[k];
					}
				}
				query = (query!=='')? '?' + query.substr(1, query.length):'';
				console.log(query)
				elements.eq(i).children().filter('span.query').eq(0).text(query);
				object = {
					"object" :elements.eq(i),
					"type"   :"GET",
					"data"   :"",
					"success":s,
					"error"  :e
				};
				$.jsonengine.fn.basic.base(object);
				elements.eq(i).children().filter('span.query').eq(0).text(tmp);
			}
			return this;
		}
	});
})(jQuery);

/**
 * jQuery.jsonengine bind event.
 */
$(function() {
	//データ表示
	$('*:[class*=_je_]:not(form:[class*=_je_])')._LOAD();

	//イベント割り当て　コマンドボタン
	$('form[class*=_je_]:not(form.search)').find('._GET').click(function(){
		$(this)._GET();
	});
	$('form[class*=_je_]:not(form.search)').find('._POST').click(function(){
		$(this)._POST();
	});
	$('form[class*=_je_]:not(form.search)').find('._PUT').click(function(){
		$(this)._PUT();
	});
	$('form[class*=_je_]:not(form.search)').find('._DELETE').click(function(){
		$(this)._DELETE();
	});
	$('form[class*=_je_]').find('._SEARCH').click(function(){
		$(this)._SEARCH();
	});
//	$('何に割り当てよう？').click(function(){
//		$('*:[class*=_je_]:not(form:[class*=_je_])')._LOAD();
//	});

	//submitをキャンセル

	$('form').submit(function(){
		return false;
	});
});
